package ljl.bilibili.gateway.util;

import io.jsonwebtoken.*;
import lombok.extern.slf4j.Slf4j;

import java.util.*;

import static ljl.bilibili.gateway.constant.Constant.*;
@Slf4j
public class JwtUtil {

    /**
     * 生成短jwt令牌
     * 该方法用于创建一个具有较短过期时间的JWT令牌
     * 主要用于需要频繁刷新或短期使用的场景
     */
    public static String generateShortToken(Integer userId) {
        return generateToken(userId, SHORT_TOKEN_EXPIRATION);
    }
    /**
     * 生成长jwt令牌
     * 该方法用于创建一个具有较长过期时间的JWT令牌
     * 主要用于需要较长有效期的场景，如登录或会话
     */
    public static String generateLongToken(Integer userId) {
        return generateToken(userId, LONG_TOKEN_EXPIRATION);
    }
    /**
     * 生成jwt令牌
     * 该方法根据用户ID和指定的过期时间来生成JWT令牌
     */
    private static String generateToken(Integer userId, int expirationTime) {
        //创建声明信息，设置角色和用户ID
        Map<String, Object> claims = new HashMap<>(1);
        claims.put(JWT_ROLE, JWT_ROLE_NAME);//设置角色为普通用户
        claims.put(USERIDENTITY,userId);//设置用户ID
        //生成JWT令牌并返回
        return Jwts.builder()
                .setClaims(claims)//设置声明信息
                .setSubject(TOKEN_SUBJECT)//设置主题
                .setIssuedAt(new Date(System.currentTimeMillis()))//设置签发时间
                .setExpiration(new Date(System.currentTimeMillis() + expirationTime))//设置过期时间
                .signWith(SignatureAlgorithm.HS512, SECRET_KEY)//设置签名算法
                .compact();//将JWT压缩为字符串形式
    }

    /**
     * 从token中获取声明
     * 该方法用于解析JWT令牌并从中提取声明
     */
    public static Claims getClaimsFromToken(String token) {
        //解析JWT令牌，并返回声明信息
        Claims claims = Jwts.parser()
                .setSigningKey(SECRET_KEY)//设置签名密钥
                .parseClaimsJws(token)//解析JWT令牌
                .getBody();//返回声明信息
        return claims;
    }
    /**
     * 校验jwt令牌是否合法
     * 该方法验证JWT令牌的有效性，包括签名和过期时间
     */
    public static boolean validateToken(String token) {
        try {
            Date date=new Date();
            //解析JWT令牌并获取过期时间
            Date tokenExpirationTime=Jwts.parser().setSigningKey(SECRET_KEY).parseClaimsJws(token).getBody().getExpiration();
            //判断令牌是否过期
            if(date.getTime()-tokenExpirationTime.getTime()>0){
                return false;
            }
            return true;
        } catch (ExpiredJwtException | SignatureException e) {
            log.info("jwtError");
            return false;
        } catch (JwtException e) {
            log.info("jwtError");
            return false;
        }
    }
    /**
     * 刷新token
     * 该方法用于刷新JWT令牌，根据传入的类型生成相应过期时间的新令牌
     */
    public static String refreshToken(String longToken,Integer type) {
        //校验旧令牌是否有效
        if (validateToken(longToken)) {
            //从旧令牌中获取用户ID
            Integer userId = getClaimsFromToken(longToken).get(USERIDENTITY,Integer.class);
            //根据刷新类型生成新令牌
            if(type==0){
                return generateShortToken(userId);
            }else {
                return generateLongToken(userId);
            }
        } else {
            throw new JwtException("Invalid long token");
        }
    }
}
